#ifndef ENUMCONVERTER_H_
#define ENUMCONVERTER_H_

#include <e32std.h>

#include "EnumConverterDefs.h"
#include "EnumConverterCleanup.h"

template<typename EnumType, typename ConversionType = TDesC8 const &>
struct EnumDefinition
    {
    struct Mapping {
        Mapping(EnumType aVal, ConversionType aStr)
          : iVal(aVal), iConv(aStr) {}
        
        EnumType const iVal;
        ConversionType iConv;
    };
    
    typedef RArray<Mapping> ValueMap;
    };

// This class needs to be specialized for different enum types
template<typename EnumType, typename ConversionType = TDesC8 const &>
struct EnumImplementation
    {
    /* Implement a function like this in specializations: 
    static void FillMapL(typename EnumDefinition<EnumType, ConversionType>::ValueMap &) {}
    */
    };

template<typename EnumType, typename ConversionType = TDesC8 const &>
class EnumConverter
    {
public:

    static EnumType Conv(ConversionType aConv)
        {
        ValueMap const & map(GetMap());
        TInt count = map.Count();
        for(TInt i = 0; i < count; ++i)
            {
            if(map[i].iConv == aConv) { return map[i].iVal; } 
            }
        User::Panic(KEnumConverter, KErrNotFound);
        }
    
    static ConversionType Conv(EnumType aVal)
        {
        ValueMap const & map(GetMap());
        TInt count = map.Count();
        for(TInt i = 0; i < count; ++i)
            {
            if(map[i].iVal == aVal) { return map[i].iConv; } 
            }
        User::Panic(KEnumConverter, KErrNotFound);
        }
    
private:
    typedef typename EnumDefinition<EnumType, ConversionType>::ValueMap ValueMap;
    
    static ValueMap const & GetMap()
        {
        static ValueMap map;
        if(map.Count() == 0)
            {
            REnumConverterCleanup & cleanup(REnumConverterCleanup::Instance());
            TRAPD(err, cleanup.AddItemL(map));
            if(err != KErrNone) { User::Panic(KEnumConverter, err); }
            TRAP(err, (EnumImplementation<EnumType, ConversionType>::FillMapL(map)));
            if(err != KErrNone) { User::Panic(KEnumConverter, err); }
            }
        return map;
        }
    };

#endif /* ENUMCONVERTER_H_ */
